﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace SimpleORM
{
    public class UpdateLambdaTranslator : LambdaTranslator
    {
        #region Properties

        public Type ObjectType { get; private set; }
        public List<string> ColumnNames { get; private set; }

        #endregion

        #region Ctor

        public UpdateLambdaTranslator()
        {
            ColumnNames = new List<string>();
        }

        #endregion

        #region Methods

        #region Methods - Public

        public override void Translate(Expression expression)
        {
            var lambda = (expression as MethodCallExpression).FindLambda();
            Expression exp = Evaluator.PartialEvalWithoutMemberInit(lambda);

            var isC = exp is ConstantExpression;
            if (isC)
                throw new NotSupportedException();

            Visit(exp);

            ObjectContext oct = ObjectContextDictionary.Get(ObjectType);
            if (oct.IsAnonymousClass)
                oct = ObjectContextDictionary.Get((((expression as MethodCallExpression).
                    FindFirst().Arguments[0] as ConstantExpression).Value as IQueryable).ElementType);

            IScriptFactory f = DataSource.CreateScriptFactory();
            IScriptFactory target = f.SchemaObject(oct.Schema, oct.TableName);
            IScriptFactory values = null;

            List<IScriptFactory> items = Stack.ToList();
            items.Reverse();
            for (int i = 0; i < items.Count; i++)
            {
                string colName = ColumnNames[i];

                if (oct.Columns[colName].DataColumn.Auto)
                    continue;

                IScriptFactory value = f.Constant(oct.Columns[colName].DataColumn.ColumnName).
                                         Stress().
                                         Concat(items[i], " = ");

                if (values == null)
                    values = value;
                else
                    values = values.Concat(value, ", ");
            }

            Result = f.Update(target, values);
        }

        #endregion

        #region Methods - Visit

        protected override NewExpression VisitNew(NewExpression n)
        {
            ObjectType = n.Type;
            foreach (var item in n.Members)
                ColumnNames.Add(item.Name);

            return base.VisitNew(n);
        }

        protected override Expression VisitMemberInit(MemberInitExpression init)
        {
            ObjectType = init.NewExpression.Type;
            foreach (var item in init.Bindings)
                ColumnNames.Add(item.Member.Name);

            return base.VisitMemberInit(init);
        }


        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            Type type = m.FindFirst().Arguments[0].Type;

            if (type.IsKindOf(typeof(IQueryable)))
            {
                ExpressionTranslater t = DataSource.CreateExpressionTranslater();
                t.Translate(new QueryableExpressionExpander().Expand(m));

                Stack.Push(t.Result.Bracket());

                return m;
            }

            return base.VisitMethodCall(m);
        }

        #endregion

        #endregion
    }
}
